home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / util / Deserializer.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  14.0 KB  |  424 lines  |  [TEXT/CWIE]

  1. // Deserializer.java
  2. // By Ned Etcode
  3. // Copyright 1996, 1997 Netscape Communications Corp. All rights reserved.
  4.  
  5. package netscape.util;
  6.  
  7. import java.io.InputStream;
  8. import java.io.IOException;
  9. import java.io.FilterInputStream;
  10. import java.io.StringBufferInputStream;
  11.  
  12.  
  13. /** FilterInputStream subclass that can deserialize Hashtables, Vectors,
  14.   * arrays, and Strings from an ASCII stream.  The serialization format is very
  15.   * similar to the output of Hashtable's and Vector's <b>toString()</b>
  16.   * methods, except strings with non-alphanumeric characters are quoted and
  17.   * special characters are escaped so that the output can be unambiguously
  18.   * deserialized.
  19.   * @see Serializer
  20.   */
  21. public class Deserializer extends FilterInputStream {
  22.     private TokenGenerator tokenGenerator;
  23.  
  24.  
  25.     /* static methods */
  26.  
  27.  
  28.     /** Convenience method for creating a Deserializer taking its input from
  29.       * <b>inputStream</b>.  This method only returns <b>null</b> on error
  30.       * instead of throwing an exception.
  31.       */
  32.     public static Object readObject(InputStream inputStream) {
  33.         Object object;
  34.         Deserializer deserializer;
  35.  
  36.         try {
  37.             deserializer = new Deserializer(inputStream);
  38.             object = deserializer.readObject();
  39.         } catch (IOException e) {
  40.             object = null;
  41.         } catch (DeserializationException e) {
  42.             object = null;
  43.         }
  44.         return object;
  45.     }
  46.  
  47.  
  48.  
  49.     /* constructors */
  50.  
  51.  
  52.     /** Constructs a Deserializer that takes its input from <b>inputStream</b>.
  53.       */
  54.     public Deserializer(InputStream inputStream) {
  55.         super(inputStream);
  56.         tokenGenerator = new TokenGenerator(inputStream);
  57.     }
  58.  
  59.     /** Convenience method for deserializing from the string
  60.       * <b>serialization</b>. Returns <b>null</b> on error.
  61.       */
  62.     public static Object deserializeObject(String serialization) {
  63.         StringBufferInputStream in;
  64.  
  65.         if (serialization == null)
  66.             return null;
  67.  
  68.         in = new StringBufferInputStream(serialization);
  69.         return readObject((InputStream)in);
  70.     }
  71.  
  72.     /** Deserializes the next Dictionary, array, Vector, or String from the
  73.       * current input stream.
  74.       */
  75.     public Object readObject() throws IOException, DeserializationException {
  76.         return readObjectInternal();
  77.     }
  78.  
  79.     private final Object readObjectInternal() throws IOException,
  80.                                                 DeserializationException {
  81.         int token;
  82.  
  83.         if(!tokenGenerator.hasMoreTokens())
  84.             return null;
  85.  
  86.         token = tokenGenerator.nextToken();
  87.         switch(token) {
  88.             case TokenGenerator.STRING_TOKEN:
  89.                 return stringForToken();
  90.             case TokenGenerator.ARRAY_BEGIN_TOKEN:
  91.                 return readArray();
  92.             case TokenGenerator.VECTOR_BEGIN_TOKEN:
  93.                 return readVector();
  94.             case TokenGenerator.HASHTABLE_BEGIN_TOKEN:
  95.                 return readHashtable();
  96.             default:
  97.                 syntaxError();
  98.                 return null;
  99.         }
  100.     }
  101.  
  102.     private final void readKeyValuePair(Hashtable result) throws IOException,
  103.                                                     DeserializationException {
  104.         Object key;
  105.         Object value;
  106.         int token;
  107.  
  108.         key = readObjectInternal();
  109.         if(key == null)
  110.             unterminatedExpression();
  111.  
  112.         if(!tokenGenerator.hasMoreTokens()) {
  113.             unterminatedExpression();
  114.         }
  115.  
  116.         token = tokenGenerator.nextToken();
  117.         if(token != TokenGenerator.HASHTABLE_KEY_VALUE_SEP_TOKEN) {
  118.             syntaxError();
  119.         }
  120.  
  121.         if(!tokenGenerator.hasMoreTokens()) {
  122.             unterminatedExpression();
  123.         }
  124.  
  125.         value = readObjectInternal();
  126.         if(value == null)
  127.             unterminatedExpression();
  128.  
  129.         result.put(key,value);
  130.  
  131.         if(!tokenGenerator.hasMoreTokens()) {
  132.             unterminatedExpression();
  133.         }
  134.  
  135.         token = tokenGenerator.peekNextToken();
  136.         if (token == TokenGenerator.HASHTABLE_KEY_VALUE_END_TOKEN ||
  137.             token == TokenGenerator.GENERIC_SEP_TOKEN)
  138.             tokenGenerator.nextToken();
  139.     }
  140.  
  141.     private final Hashtable readHashtable() throws IOException,
  142.                                                 DeserializationException {
  143.         Hashtable result = new Hashtable();
  144.         int token;
  145.  
  146.         while(true) {
  147.             if (!tokenGenerator.hasMoreTokens()) {
  148.                 unterminatedExpression();
  149.             }
  150.  
  151.             token = tokenGenerator.peekNextToken();
  152.             if (token == TokenGenerator.HASHTABLE_END_TOKEN) {
  153.                 tokenGenerator.nextToken();
  154.                 return result;
  155.             }
  156.  
  157.             readKeyValuePair( result );
  158.         }
  159.     }
  160.  
  161.     private final Vector readVector() throws IOException,
  162.                                                     DeserializationException {
  163.         Vector result = new Vector();
  164.         int token;
  165.         boolean justAddedObject=false;
  166.         Object object;
  167.  
  168.         while (true) {
  169.             if (!tokenGenerator.hasMoreTokens()) {
  170.                 unterminatedExpression();
  171.             }
  172.  
  173.             token = tokenGenerator.peekNextToken();
  174.             if (token == TokenGenerator.VECTOR_END_TOKEN) {
  175.                 tokenGenerator.nextToken();
  176.                 return result;
  177.             }
  178.  
  179.             if (token == TokenGenerator.GENERIC_SEP_TOKEN) {
  180.                 tokenGenerator.nextToken();
  181.                 if (justAddedObject) {
  182.                     justAddedObject = false;
  183.                 } else {
  184.                     syntaxError();
  185.                 }
  186.             } else if (justAddedObject) {
  187.                 syntaxError();
  188.             }
  189.  
  190.             object = readObjectInternal();
  191.             if (object != null) {
  192.                 result.addElement(object);
  193.                 justAddedObject = true;
  194.             }
  195.         }
  196.     }
  197.  
  198.     private final Object[] readArray() throws IOException,
  199.                                                 DeserializationException {
  200.         Object buf[] = new Object[16];
  201.         int bufIndex=0;
  202.         Object obj;
  203.         int nextToken;
  204.         boolean justAddedObject=false;
  205.  
  206.         while (true) {
  207.             if (!tokenGenerator.hasMoreTokens()) {
  208.                 unterminatedExpression();
  209.             }
  210.  
  211.             nextToken = tokenGenerator.peekNextToken();
  212.             if (nextToken == TokenGenerator.ARRAY_END_TOKEN) {
  213.                 tokenGenerator.nextToken();
  214.                 Object result[] = new Object[bufIndex];
  215.                 System.arraycopy(buf, 0, result, 0, bufIndex);
  216.                 return result;
  217.             } else if (nextToken == TokenGenerator.GENERIC_SEP_TOKEN) {
  218.                 tokenGenerator.nextToken();
  219.                 if (justAddedObject) {
  220.                     justAddedObject=false;
  221.                 } else {
  222.                     syntaxError();
  223.                 }
  224.             } else if (justAddedObject) {
  225.                 syntaxError();
  226.             }
  227.  
  228.             // This code is here and not in readObjectInternal() because we
  229.             // only want to allow null in arrays.  It should be a syntax error
  230.             // for the null token to appear elsewhere.
  231.  
  232.             nextToken = tokenGenerator.peekNextToken();
  233.             if (nextToken == TokenGenerator.NULL_VALUE_TOKEN) {
  234.                 tokenGenerator.nextToken();
  235.                 obj = null;
  236.             } else
  237.                 obj = readObjectInternal();
  238.  
  239.             buf[bufIndex++] = obj;
  240.             if (bufIndex == buf.length) {
  241.                 Object newBuf[] = new Object[buf.length * 2];
  242.                 System.arraycopy(buf, 0, newBuf, 0, buf.length);
  243.                 buf = newBuf;
  244.             }
  245.             justAddedObject = true;
  246.         }
  247.     }
  248.  
  249.     private final String stringForToken() throws DeserializationException{
  250.         byte str[] = tokenGenerator.bytesForLastToken();
  251.  
  252.         if (str == null || str.length == 0 ) {
  253.             internalInconsistency("empty string");
  254.         }
  255.  
  256.         if ( str[0] == '"' ) {
  257.             byte b;
  258.             char charBuf[] = new char[32];
  259.             int charBufIndex=0;
  260.             int i,c;
  261.  
  262.             for (i=1,c=str.length-1;i<c;i++) {
  263.                 b = str[i];
  264.                 if ( b == '\\' ) {
  265.                     byte nextByte = 0;
  266.                     char nextChar = 0;
  267.                     if(++i < c )
  268.                         nextByte = str[i];
  269.                     else
  270.                         malformedString();
  271.  
  272.                     switch(nextByte) {
  273.                         case '"':
  274.                             nextChar = (char)nextByte;
  275.                             break;
  276.                         case 't':
  277.                             nextChar = '\t';
  278.                             break;
  279.                         case 'n':
  280.                             nextChar = '\n';
  281.                             break;
  282.                         case 'r':
  283.                             nextChar = '\r';
  284.                             break;
  285.                         case '\\':
  286.                             nextChar = '\\';
  287.                             break;
  288.                         case 'u':
  289.                             byte one=0,two=0,three=0,four=0;
  290.  
  291.                             if (++i < c )
  292.                                 one = str[i];
  293.                             else
  294.                                 malformedString();
  295.  
  296.                             if (++i < c)
  297.                                 two = str[i];
  298.                             else
  299.                                 malformedString();
  300.  
  301.                             if (++i < c)
  302.                                 three = str[i];
  303.                             else
  304.                                 malformedString();
  305.  
  306.                             if (++i < c)
  307.                                 four = str[i];
  308.                             else
  309.                                 malformedString();
  310.  
  311.                             if (isHexa(one) && isHexa(two) && isHexa(three) &&
  312.                                 isHexa(four)) {
  313.                                 nextChar =
  314.                                         (char)((asciiToFourBits(one) << 12) |
  315.                                                (asciiToFourBits(two) << 8)  |
  316.                                                (asciiToFourBits(three) << 4) |
  317.                                                asciiToFourBits(four));
  318.                                 break;
  319.                             } else
  320.                                 malformedString();
  321.                                 break;
  322.  
  323.                         default:
  324.                             byte up=0,middle=0,low=0;
  325.  
  326.                             up = nextByte;
  327.                             if (++i < c )
  328.                                 middle = str[i];
  329.                             else
  330.                                 i--;
  331.  
  332.                             if (++i < c )
  333.                                 low = str[i];
  334.                             else
  335.                                 i--;
  336.  
  337.                             if (up >= '0' && up <= '7' &&
  338.                                 middle >= '0' && middle <= '7' &&
  339.                                 low >= '0' && low <= '7' ) {
  340.                                 nextChar = (char)(((up - '0') << 6) |
  341.                                            ((middle - '0') << 3) |
  342.                                            (low - '0'));
  343.                                 break;
  344.                             } else {
  345.                                 malformedString();
  346.                             }
  347.  
  348.                             break;
  349.                     }
  350.  
  351.                     charBuf[charBufIndex++] = nextChar;
  352.                     if (charBufIndex == charBuf.length ) {
  353.                         char newCharBuf[]  = new char[charBuf.length * 2];
  354.                         System.arraycopy(charBuf, 0, newCharBuf, 0,
  355.                                          charBuf.length);
  356.                         charBuf = newCharBuf;
  357.                     }
  358.                 } else {
  359.                     charBuf[charBufIndex++] = (char)b;
  360.                     if (charBufIndex == charBuf.length ) {
  361.                         char newCharBuf[]  = new char[charBuf.length * 2];
  362.                         System.arraycopy(charBuf, 0, newCharBuf, 0,
  363.                                          charBuf.length);
  364.                         charBuf = newCharBuf;
  365.                     }
  366.                 }
  367.             }
  368.  
  369.             return new String(charBuf,0,charBufIndex);
  370.         } else {
  371.             return new String(str,0);
  372.         }
  373.     }
  374.  
  375.     private final boolean isHexa(byte b) {
  376.         if ((b >= '0' && b <= '9') ||
  377.             (b >= 'a' && b <= 'f') ||
  378.             (b >= 'A' && b <= 'F') )
  379.             return true;
  380.         else
  381.             return false;
  382.     }
  383.  
  384.     private final byte asciiToFourBits(byte b) {
  385.         if( b >= '0' && b <= '9' )
  386.             return (byte)(b - '0');
  387.         else if( b >= 'a' && b <= 'f')
  388.             return (byte)(b - 'a'+0xa);
  389.         else
  390.             /* We assume that byte b makes sense... Caller should test it */
  391.             return (byte)(b - 'A'+0xa);
  392.     }
  393.  
  394.     private void malformedString() throws DeserializationException {
  395.         int line = tokenGenerator.lineForLastToken();
  396.  
  397.         throw new DeserializationException("Malformed string at line " + line +
  398.                                            ":" +
  399.                     new String(tokenGenerator.bytesForLastToken(),0), line);
  400.     }
  401.  
  402.     private void syntaxError() throws DeserializationException {
  403.         int line = tokenGenerator.lineForLastToken();
  404.         throw new DeserializationException("Syntax error at line " + line,
  405.                                             line);
  406.     }
  407.  
  408.     private void internalInconsistency(String type) throws
  409.                                                     DeserializationException {
  410.         int line = tokenGenerator.lineForLastToken();
  411.  
  412.         throw new DeserializationException(
  413.             "Internal inconsistency exception. Please report this problem. " +
  414.             type + " " + line, line);
  415.     }
  416.  
  417.     private void unterminatedExpression() throws DeserializationException {
  418.         int line = tokenGenerator.lineForLastToken();
  419.  
  420.         throw new DeserializationException("Unterminated expression at line " +
  421.                                            line, line);
  422.     }
  423. }
  424.